package com.zmy.seursstarter.core;

import com.zmy.seursstarter.HttpTool.HttpClientUtil;
import com.zmy.seursstarter.SeuRSProperties;
import lombok.Data;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import javax.crypto.Cipher;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.List;

@Data
public class SeuAuth {
    //登录公钥
    private String publicKey;

    //讲座需要的cookie
    private String gs_sessionId;


    @Autowired
    private SeuRSProperties seuRsProperties;

    private HttpPost getHttpPost(String url) throws UnsupportedEncodingException {
        HttpPost post = new HttpPost(url);
        post.setHeader("Content-Type", this.seuRsProperties.getHeaderContentType());
        post.setHeader("User-Agent", this.seuRsProperties.getHeaderUserAgent());
        post.setEntity(new StringEntity("{}"));
        return post;
    }

    private HttpClientContext getPublicKeyByContext(){
        try {
            HttpPost post = getHttpPost(this.seuRsProperties.getPublicKeyUrl());

            HttpClientContext context = HttpClientContext.create();
            String response = HttpClientUtil.getHttpClient().execute(post,
                    httpResponse -> EntityUtils.toString(httpResponse.getEntity()),
                    context);

            if (response == null || !response.contains("\"publicKey\"")) {
                throw new Exception("Failed to get public key");
            }

            JSONObject jsonResponse = new JSONObject(response);
            this.publicKey = jsonResponse.getString("publicKey");

            return context;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private String getRsaEncrypt(String message){
        try {
            String pubKey = this.publicKey.replace('-', '+').replace('_', '/');
            byte[] keyBytes = Base64.getDecoder().decode(pubKey);
            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pub_Key = keyFactory.generatePublic(spec);

            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, pub_Key);

            byte[] cipherText = cipher.doFinal(message.getBytes());
            return Base64.getEncoder().encodeToString(cipherText);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 仅仅进行登录认证
     * @param username
     * @param password
     */
    public boolean auth(String username, String password) {
        try {
            HttpClientContext context = getPublicKeyByContext();
            String rsaEncryptPassword = getRsaEncrypt(password);

            HttpPost post = getHttpPost(this.seuRsProperties.getCasLoginUrl());
            JSONObject data = new JSONObject();
            data.put("captcha", "");
            data.put("loginType", "account");
            data.put("mobilePhoneNum", "");
            data.put("mobileVerifyCode", "");
            data.put("password", rsaEncryptPassword);
            data.put("rememberMe", false);
            data.put("service", "");
            data.put("username", username);
            data.put("wxBinded", false);
            post.setEntity(new StringEntity(data.toString()));

            String response = HttpClientUtil.getHttpClient().execute(post,
                    httpResponse -> EntityUtils.toString(httpResponse.getEntity()),
                    context);
            JSONObject resJson = new JSONObject(response);

            if (resJson.getInt("code") != 200) {
                throw new IOException("HTTP error: " + resJson.getInt("code") + " " + resJson.getString("info"));
            }
            if (!resJson.getBoolean("success")) {
                throw new IOException("Authentication failed: " + resJson.getString("info"));
            }
            List<Cookie> cookies = context.getCookieStore().getCookies();
            System.out.println(cookies);
            return true;
        } catch (JSONException | IOException e) {
            System.err.println("Failed to authenticate: " + e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 讲座登录认证，获取cookie
     * @param username
     * @param password
     */
    public boolean auth_lecture(String username, String password) {
        try {
            HttpClientContext context = getPublicKeyByContext();
            String rsaEncryptPassword = getRsaEncrypt(password);

            HttpPost post = getHttpPost(this.seuRsProperties.getCasLoginUrl());
            JSONObject data = new JSONObject();
            data.put("captcha", "");
            data.put("loginType", "account");
            data.put("mobilePhoneNum", "");
            data.put("mobileVerifyCode", "");
            data.put("password", rsaEncryptPassword);
            data.put("rememberMe", false);
            data.put("service", this.seuRsProperties.getLectureUrl());
            data.put("username", username);
            data.put("wxBinded", false);
            post.setEntity(new StringEntity(data.toString()));

            String response = HttpClientUtil.getHttpClient().execute(post,
                    httpResponse -> EntityUtils.toString(httpResponse.getEntity()),
                    context);
            JSONObject resJson = new JSONObject(response);

            if (resJson.getInt("code") != 200) {
                throw new IOException("HTTP error: " + resJson.getInt("code") + " " + resJson.getString("info"));
            }
            if (!resJson.getBoolean("success")) {
                throw new IOException("Authentication failed: " + resJson.getString("info"));
            }

            String redirectUrl = resJson.optString("redirectUrl", null);
            if (redirectUrl != null && !redirectUrl.isEmpty()) {
                redirectUrl = URLDecoder.decode(redirectUrl, StandardCharsets.UTF_8);
            }

            HttpClientUtil.getHttpClientWithoutSSL().execute(new HttpGet(redirectUrl), context);
            this.gs_sessionId = context.getCookieStore().getCookies().get(1).getValue();
            if (!this.gs_sessionId.isEmpty()) {
                return true;
            }

        } catch (JSONException | IOException e) {
            System.err.println("Failed to authenticate: " + e.getMessage());
            throw new RuntimeException(e);
        }
        return false;
    }
}
